#include "sdk.h"
#include "filefilters.h"

CompileTargetBase::CompileTargetBase()
  : m_TargetType( ttExecutable ),
    m_RunHostApplicationInTerminal( false ),
    m_PrefixGenerationPolicy( tgfpPlatformDefault ),
    m_ExtensionGenerationPolicy( tgfpPlatformDefault ) {
  for( int i = 0; i < static_cast<int>( ortLast ); ++i ) {
    m_OptionsRelation[i] = orAppendToParentOptions;
  }
  m_MakeCommands[mcBuild] = _T( "$make -f $makefile $target" );
  m_MakeCommands[mcCompileFile] = _T( "$make -f $makefile $file" );
  m_MakeCommands[mcClean] = _T( "$make -f $makefile clean$target" );
  m_MakeCommands[mcDistClean] = _T( "$make -f $makefile distclean$target" );
  m_MakeCommands[mcAskRebuildNeeded] = _T( "$make -q -f $makefile $target" );
  m_MakeCommands[mcSilentBuild] = m_MakeCommands[mcBuild] + _T( " > $(CMD_NULL)" );
  m_MakeCommandsModified = false;
}

CompileTargetBase::~CompileTargetBase() {
}

void CompileTargetBase::SetTargetFilenameGenerationPolicy( TargetFilenameGenerationPolicy prefix,
    TargetFilenameGenerationPolicy extension ) {
  m_PrefixGenerationPolicy = prefix;
  m_ExtensionGenerationPolicy = extension;
  SetModified( true );
}

void CompileTargetBase::GetTargetFilenameGenerationPolicy( TargetFilenameGenerationPolicy& prefixOut,
    TargetFilenameGenerationPolicy& extensionOut ) const {
  prefixOut = m_PrefixGenerationPolicy;
  extensionOut = m_ExtensionGenerationPolicy;
}

const wxString& CompileTargetBase::GetFilename() const {
  return m_Filename;
}

const wxString& CompileTargetBase::GetTitle() const {
  return m_Title;
}

void CompileTargetBase::SetTitle( const wxString& title ) {
  if( m_Title == title ) {
    return;
  }
  m_Title = title;
  SetModified( true );
}

void CompileTargetBase::SetOutputFilename( const wxString& filename ) {
  if( filename.IsEmpty() ) {
    m_OutputFilename = SuggestOutputFilename();
    SetModified( true );
    return;
  } else if( m_OutputFilename == filename ) {
    return;
  }
  m_OutputFilename = UnixFilename( filename );
  GenerateTargetFilename( m_OutputFilename );
  SetModified( true );
}

void CompileTargetBase::SetImportLibraryFilename( const wxString& filename ) {
  if( filename.IsEmpty() ) {
    m_ImportLibraryFilename = _T( "$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME)" );
    SetModified( true );
    return;
  } else if( m_ImportLibraryFilename == filename ) {
    return;
  }
  m_ImportLibraryFilename = UnixFilename( filename );
}

void CompileTargetBase::SetDefinitionFileFilename( const wxString& filename ) {
  if( filename.IsEmpty() ) {
    m_DefinitionFileFilename = _T( "$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME)" );
    SetModified( true );
    return;
  } else if( m_DefinitionFileFilename == filename ) {
    return;
  }
  m_DefinitionFileFilename = UnixFilename( filename );
}

void CompileTargetBase::SetWorkingDir( const wxString& dirname ) {
  if( m_WorkingDir == dirname ) {
    return;
  }
  m_WorkingDir = UnixFilename( dirname );
  SetModified( true );
}

void CompileTargetBase::SetObjectOutput( const wxString& dirname ) {
  if( m_ObjectOutput == dirname ) {
    return;
  }
  m_ObjectOutput = UnixFilename( dirname );
  SetModified( true );
}

void CompileTargetBase::SetDepsOutput( const wxString& dirname ) {
  if( m_DepsOutput == dirname ) {
    return;
  }
  m_DepsOutput = UnixFilename( dirname );
  SetModified( true );
}

OptionsRelation CompileTargetBase::GetOptionRelation( OptionsRelationType type ) const {
  return m_OptionsRelation[type];
}

void CompileTargetBase::SetOptionRelation( OptionsRelationType type, OptionsRelation rel ) {
  if( m_OptionsRelation[type] == rel ) {
    return;
  }
  m_OptionsRelation[type] = rel;
  SetModified( true );
}

wxString CompileTargetBase::GetOutputFilename() {
  if( m_TargetType == ttCommandsOnly ) {
    return wxEmptyString;
  }
  if( m_OutputFilename.IsEmpty() ) {
    m_OutputFilename = SuggestOutputFilename();
  }
  return m_OutputFilename;
}

wxString CompileTargetBase::SuggestOutputFilename() {
  wxString suggestion;
  switch( m_TargetType ) {
    case ttConsoleOnly:
    case ttExecutable:
      suggestion = GetExecutableFilename();
      break;
    case ttDynamicLib:
      suggestion = GetDynamicLibFilename();
      break;
    case ttStaticLib:
      suggestion = GetStaticLibFilename();
      break;
    case ttNative:
      suggestion = GetNativeFilename();
      break;
    case ttCommandsOnly:
    default:
      suggestion.Clear();
      break;
  }
  wxFileName fname( suggestion );
  return UnixFilename( fname.GetFullName() );
}

wxString CompileTargetBase::GetWorkingDir() {
  if( m_TargetType != ttConsoleOnly && m_TargetType != ttExecutable && m_TargetType != ttDynamicLib ) {
    return wxEmptyString;
  }
  wxString out;
  if( m_WorkingDir.IsEmpty() ) {
    out = GetOutputFilename();
    return wxFileName( out ).GetPath( wxPATH_GET_VOLUME );
  }
  return m_WorkingDir;
}

wxString CompileTargetBase::GetObjectOutput() const {
  if( m_TargetType == ttCommandsOnly ) {
    return wxEmptyString;
  }
  wxString out;
  if( m_ObjectOutput.IsEmpty() ) {
    out = GetBasePath();
    if( out.IsEmpty() || out.Matches( _T( "." ) ) ) {
      return _T( ".objs" );
    } else {
      return out + wxFileName::GetPathSeparator() + _T( ".objs" );
    }
  }
  return m_ObjectOutput;
}

wxString CompileTargetBase::GetDepsOutput() const {
  if( m_TargetType == ttCommandsOnly ) {
    return wxEmptyString;
  }
  wxString out;
  if( m_DepsOutput.IsEmpty() ) {
    out = GetBasePath();
    if( out.IsEmpty() || out.Matches( _T( "." ) ) ) {
      return _T( ".deps" );
    } else
    { return out + wxFileName::GetPathSeparator() + _T( ".deps" ); }
  }
  return m_DepsOutput;
}

void CompileTargetBase::GenerateTargetFilename( wxString& filename ) const {
  if( m_PrefixGenerationPolicy    == tgfpNone
      && m_ExtensionGenerationPolicy == tgfpNone ) {
    return;
  }
  wxFileName fname( filename );
  filename.Clear();
  filename << fname.GetPath( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR );
  switch( m_TargetType ) {
    case ttConsoleOnly:
    case ttExecutable: {
      if( m_ExtensionGenerationPolicy == tgfpPlatformDefault ) {
        filename << fname.GetName();
        filename << FileFilters::EXECUTABLE_DOT_EXT;
      } else
      { filename << fname.GetFullName(); }
      break;
    }
    case ttDynamicLib: {
      if( m_PrefixGenerationPolicy == tgfpPlatformDefault ) {
        wxString prefix = _T( "lib" );
        if( !prefix.IsEmpty() && !fname.GetName().StartsWith( prefix ) ) {
          filename << prefix;
        }
      }
      if( m_ExtensionGenerationPolicy == tgfpPlatformDefault ) {
        filename << fname.GetName() << FileFilters::DYNAMICLIB_DOT_EXT;
      } else
      { filename << fname.GetFullName(); }
      break;
    }
    case ttNative: {
      if( m_ExtensionGenerationPolicy == tgfpPlatformDefault ) {
        filename << fname.GetName() << FileFilters::NATIVE_DOT_EXT;
      } else
      { filename << fname.GetFullName(); }
      break;
    }
    case ttStaticLib: {
      if( m_PrefixGenerationPolicy == tgfpPlatformDefault ) {
        Compiler* compiler = CompilerFactory::GetCompiler( m_CompilerId );
        wxString prefix = compiler ? compiler->GetSwitches().libPrefix : _T( "" );
        if( !prefix.IsEmpty() && !fname.GetName().StartsWith( prefix ) ) {
          filename << prefix;
        }
      }
      if( m_ExtensionGenerationPolicy == tgfpPlatformDefault ) {
        Compiler* compiler = CompilerFactory::GetCompiler( m_CompilerId );
        wxString Ext = compiler ? compiler->GetSwitches().libExtension : FileFilters::STATICLIB_EXT;
        filename << fname.GetName() << _T( "." ) << Ext;
      } else
      { filename << fname.GetFullName(); }
      break;
    }
    case ttCommandsOnly:
    default:
      filename.Clear();
      break;
  }
  #ifdef command_line_generation
  Manager::Get()->GetLogManager()->DebugLog( F( _T( "CompileTargetBase::GenerateTargetFilename got %s and returns: '%s'" ), fname.GetFullPath().wx_str(), filename.wx_str() ) );
  #endif
}

wxString CompileTargetBase::GetExecutableFilename() const {
  if( m_TargetType == ttCommandsOnly ) {
    return wxEmptyString;
  }
  if( m_PrefixGenerationPolicy != tgfpNone || m_ExtensionGenerationPolicy != tgfpNone ) {
    wxString out = m_Filename;
    GenerateTargetFilename( out );
    return out;
  }
  wxFileName fname( m_Filename );
  fname.SetExt( _T( "" ) );
  return fname.GetFullPath();
}

wxString CompileTargetBase::GetNativeFilename() {
  if( m_TargetType == ttCommandsOnly ) {
    return wxEmptyString;
  }
  if( m_Filename.IsEmpty() ) {
    m_Filename = m_OutputFilename;
  }
  if( m_PrefixGenerationPolicy != tgfpNone || m_ExtensionGenerationPolicy != tgfpNone ) {
    wxString out = m_Filename;
    GenerateTargetFilename( out );
    return out;
  }
  wxFileName fname( m_Filename );
  fname.SetName( fname.GetName() );
  fname.SetExt( FileFilters::NATIVE_EXT );
  return fname.GetFullPath();
}

wxString CompileTargetBase::GetDynamicLibFilename() {
  if( m_TargetType == ttCommandsOnly ) {
    return wxEmptyString;
  }
  if( m_Filename.IsEmpty() ) {
    m_Filename = m_OutputFilename;
  }
  if( m_PrefixGenerationPolicy != tgfpNone || m_ExtensionGenerationPolicy != tgfpNone ) {
    wxString out = m_Filename;
    GenerateTargetFilename( out );
    #ifdef command_line_generation
    Manager::Get()->GetLogManager()->DebugLog( F( _T( "CompileTargetBase::GetDynamicLibFilename [0] returns: '%s'" ), out.wx_str() ) );
    #endif
    return out;
  }
  wxFileName fname( m_Filename );
  fname.SetName( fname.GetName() );
  fname.SetExt( FileFilters::DYNAMICLIB_EXT );
  #ifdef command_line_generation
  Manager::Get()->GetLogManager()->DebugLog( F( _T( "CompileTargetBase::GetDynamicLibFilename [1] returns: '%s'" ), fname.GetFullPath().wx_str() ) );
  #endif
  return fname.GetFullPath();
}

wxString CompileTargetBase::GetDynamicLibImportFilename() {
  if( m_TargetType == ttCommandsOnly ) {
    return wxEmptyString;
  }
  if( m_ImportLibraryFilename.IsEmpty() ) {
    m_ImportLibraryFilename = _T( "$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME)" );
  }
  wxFileName fname( m_ImportLibraryFilename );
  #ifdef command_line_generation
  Manager::Get()->GetLogManager()->DebugLog( F( _T( "CompileTargetBase::GetDynamicLibImportFilename returns: '%s'" ), fname.GetFullPath().wx_str() ) );
  #endif
  return fname.GetFullPath();
}

wxString CompileTargetBase::GetDynamicLibDefFilename() {
  if( m_TargetType == ttCommandsOnly ) {
    return wxEmptyString;
  }
  if( m_DefinitionFileFilename.IsEmpty() ) {
    m_DefinitionFileFilename = _T( "$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME)" );
  }
  wxFileName fname( m_DefinitionFileFilename );
  #ifdef command_line_generation
  Manager::Get()->GetLogManager()->DebugLog( F( _T( "CompileTargetBase::GetDynamicLibDefFilename returns: '%s'" ), fname.GetFullPath().wx_str() ) );
  #endif
  return fname.GetFullPath();
}

wxString CompileTargetBase::GetStaticLibFilename() {
  if( m_TargetType == ttCommandsOnly ) {
    return wxEmptyString;
  }
  if( m_Filename.IsEmpty() ) {
    m_Filename = m_OutputFilename;
  }
  if( ( m_TargetType == ttStaticLib )
      && ( m_PrefixGenerationPolicy    != tgfpNone
           || m_ExtensionGenerationPolicy != tgfpNone ) ) {
    wxString out = m_Filename;
    GenerateTargetFilename( out );
    #ifdef command_line_generation
    Manager::Get()->GetLogManager()->DebugLog( F( _T( "CompileTargetBase::GetStaticLibFilename [0] returns: '%s'" ), out.wx_str() ) );
    #endif
    return out;
  }
  wxFileName fname( m_Filename );
  wxString prefix = _T( "lib" );
  wxString suffix = FileFilters::STATICLIB_EXT;
  Compiler* compiler = CompilerFactory::GetCompiler( m_CompilerId );
  if( compiler ) {
    prefix = compiler->GetSwitches().libPrefix;
    suffix = compiler->GetSwitches().libExtension;
  }
  if( !fname.GetName().StartsWith( prefix ) ) {
    fname.SetName( prefix + fname.GetName() );
  }
  fname.SetExt( suffix );
  #ifdef command_line_generation
  Manager::Get()->GetLogManager()->DebugLog( F( _T( "CompileTargetBase::GetStaticLibFilename [1] returns: '%s'" ), fname.GetFullPath().wx_str() ) );
  #endif
  return fname.GetFullPath();
}

wxString CompileTargetBase::GetBasePath() const {
  if( m_Filename.IsEmpty() ) {
    return _T( "." );
  }
  wxFileName basePath( m_Filename );
  wxString base = basePath.GetPath( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR );
  return !base.IsEmpty() ? base : _T( "." );
}

void CompileTargetBase::SetTargetType( TargetType pt ) {
  if( m_TargetType == pt ) {
    return;
  }
  m_TargetType = pt;
  m_OutputFilename = SuggestOutputFilename();
  SetModified( true );
}

TargetType CompileTargetBase::GetTargetType() const {
  return m_TargetType;
}

const wxString& CompileTargetBase::GetExecutionParameters() const {
  return m_ExecutionParameters;
}

void CompileTargetBase::SetExecutionParameters( const wxString& params ) {
  if( m_ExecutionParameters == params ) {
    return;
  }
  m_ExecutionParameters = params;
  SetModified( true );
}

const wxString& CompileTargetBase::GetHostApplication() const {
  return m_HostApplication;
}

void CompileTargetBase::SetHostApplication( const wxString& app ) {
  if( m_HostApplication == app ) {
    return;
  }
  m_HostApplication = app;
  SetModified( true );
}

bool CompileTargetBase::GetRunHostApplicationInTerminal() const {
  return m_RunHostApplicationInTerminal;
}

void CompileTargetBase::SetRunHostApplicationInTerminal( bool in_terminal ) {
  if( m_RunHostApplicationInTerminal == in_terminal ) {
    return;
  }
  m_RunHostApplicationInTerminal = in_terminal;
  SetModified( true );
}

void CompileTargetBase::SetCompilerID( const wxString& id ) {
  if( id == m_CompilerId ) {
    return;
  }
  m_CompilerId = id;
  SetModified( true );
}

void CompileTargetBase::SetMakeCommandFor( MakeCommand cmd, const wxString& make ) {
  if( m_MakeCommands[cmd] == make ) {
    return;
  }
  m_MakeCommands[cmd] = make;
  m_MakeCommandsModified = true;
  SetModified( true );
}
